#ifndef __MAPPOINT_H__
#define __MAPPOINT_H__
#include "../include/Typedef.hpp"
#include "../include/Frame.hpp"
#include "../include/Map.hpp"
#include "../include/Matcher.hpp"
#include <mutex>
using namespace std;
using namespace cv;
namespace ORBSLAM
{
    class KeyFrame;
    class Map;
    class Matcher;
    class Frame;
    class MapPoint
    {
    private:
        Map *mp_map;
        map<KeyFrame *, int> mmap_observation;
        int mn_obs;

    public:
        /* data */
        Mat mm_world_pose;
        vector<KeyFrame *> mvp_ref_keyframe;

        Mat mm_descrptor;

        bool mb_bad;
        float mf_max_distance;
        float mf_min_distance;
        Mat mm_normal_vector;

        static long unsigned int sm_curid;
        long unsigned int mn_id;

        Mat mm_world_pose_gba;
        unsigned long mn_loopKF_gba;

        unsigned long mn_localmappoint_tmpid;

        unsigned long mn_lastseen_frameid;

        Point2f m_preproj_uv_tocurframe;
        bool mb_ifproj_tocurframe;
        float mf_depth_tocurframe;
        int mn_tarcked_level;
        float mf_viewcos_tocurframe;

        mutex mmutex_feature;
        mutex mmutex_pos;
        mutex mmutex_map;

        int mn_found;
        int mn_visible;

        long mn_first_keyframe_id;

        MapPoint * mp_replaced_mpt;

        unsigned long mn_mark_fuse_id;
        unsigned long mn_mark_localba_id;
        unsigned long mn_mark_corrected_by_keyframe;
        unsigned long mn_mark_corrected_refkeyframe;
        

    public:
        MapPoint(/* args */);
        ~MapPoint();
        MapPoint(Mat &pos);
        MapPoint(Mat &pos, KeyFrame *p_keyframe, Map *p_map);
        void Set_ref_keframe(KeyFrame *p_keyframe1,KeyFrame* p_keyframe2);
        void Set_map(Map *p_map);
        void Add_key_frame(KeyFrame *p_keyframe);
        void Add_observation(KeyFrame *p_keyframe, int idx);
        void Compute_distinctive_descriptors();
        void Update_normal_and_depth();
        bool Is_bad();
        void Set_world_pose(const Mat &pos);
        Mat Get_world_pose();
        Map *Get_map();
        map<KeyFrame *, int> Get_observation();
        int Get_observation_num();
        Mat Get_descriptor();

        bool Is_in_keyframe(KeyFrame* p_keyframe);

        bool Get_found_ratio();

        void Set_bad_flag();

        Mat Get_normal();

        int Predict_scale(const float &current_dist,KeyFrame * p_keyframe);
        int Predict_scale(const float &current_dist,Frame * p_frame);

        void Replace(MapPoint* p_mpt);

        void Increase_found(int n);

        void Increase_visible(int n);

        void Erase_observation(KeyFrame* p_keyframe);

        int Get_index_in_keyframe(KeyFrame* p_keyframe);

        KeyFrame* Get_reference_keyframe();

        float Get_max_distance_invariance();
        float Get_min_distance_invariance();
    };

}
#endif // __MAPPOINT_H__